// MegaCli -AdpGetPciInfo -aN|-a0,1,2|-aALL
// PCI information for Controller、Bus Number、Device Number、Function Number

package megacli

import (
    "fmt"
    "github.com/prometheus/common/log"
    "strconv"
    "strings"
)

// 获取控制器
func GetControllers() ([]*Controller, error) {
    res, err := Run(clipath, "-AdpGetPciInfo", "-aAll", "-NoLog")
    if err != nil {
        return nil, err
    }
    return parsePCIInfo(res)
}

// 解析控制器信息
func parsePCIInfo(info string) ([]*Controller, error) {
    if info == "" {
        return nil, fmt.Errorf("can not find pci info")
    }

    var ctls []*Controller

    var ctl *Controller
    for _, line := range strings.Split(info, "\n") {
        l := strings.TrimSpace(line)

        if strings.HasPrefix(l, "PCI information for Controller") {
            if ctl != nil {
                ctls = append(ctls, ctl)
            }

            ctl = new(Controller)
            num, err := parseControllerNumber(l)
            if err != nil {
                log.Debug(err)
                continue
            }
            ctl.Number = num
        }

        if ctl == nil {
            continue
        }

        key, val, err := SplitKeyVal(line, ":")
        if err != nil {
            log.Debug(err)
            continue
        }

        num, err := strconv.ParseInt(val, 16, 64)
        if err != nil {
            continue
        }
        n := uint32(num)

        switch key {
        case "Bus Number":
            ctl.Bus = n
        case "Device Number":
            ctl.Device = n
        case "Function Number":
            ctl.Function = n
        }
    }

    if ctl != nil {
        ctls = append(ctls, ctl)
    }

    return ctls, nil
}

// 解析控制器编号信息
func parseControllerNumber(line string) (int, error) {
    field := strings.Fields(line)
    if len(field) < 1 {
        return -1, fmt.Errorf("invalid format")
    }

    num, err := strconv.Atoi(field[len(field)-1])
    if err != nil {
        return -1, err
    }

    if num < 0 {
        return -1, fmt.Errorf("invalid number")
    }

    return num, nil
}
